<!--组件：预览代码-->
<template>
  <div>
    <a-modal
      :visible="visible"
      title="预览"
      fullscreen
      hide-cancel
      unmount-on-close
      :body-style="{ height: '100%', padding: '0 24px' }"
      @cancel="onClose"
      @ok="onClose"
    >
      <a-spin :loading="loading" style="width: 100%; height: 100%">
        <a-split
          v-model:size="size"
          min="80px"
          style="width: 100%; height: 100%"
        >
          <template #first>
            <div style="white-space: nowrap">
              <a-button shape="round" @click="onCollapse">
                <icon-caret-right v-if="collapsed" />
                <icon-caret-left v-else />
              </a-button>
              <a-tree
                :data="fileTree"
                :selected-keys="selectedNodes"
                :expanded-keys="expandedNodes"
                @select="onSelectNode"
              />
            </div>
          </template>
          <template #second>
            <a-radio-group
              :model-value="activeFile"
              class="preview-code-tags"
              @change="onChangeTag"
            >
              <a-radio
                v-for="item in openedFiles"
                :key="item.key"
                :value="item.key"
              >
                <template #radio="{ checked }">
                  <a-tag :checked="checked" checkable>{{ item.title }}</a-tag>
                </template>
              </a-radio>
            </a-radio-group>
            <div style="padding: 10px 30px">
              <pre><code>{{ displayingCode }}</code></pre>
            </div>
          </template>
        </a-split>
      </a-spin>
    </a-modal>
  </div>
</template>

<script setup lang="ts" name="PreviewCodeModal">
  import { ref, watch } from 'vue';
  import { CodePreviewRecord } from '@/api/infrastructure/model/codegenModel';
  import { previewGeneratedCode } from '@/api/infrastructure/codegen';
  import { TreeNodeData } from '@arco-design/web-vue';

  const props = defineProps({
    visible: { type: Boolean, default: false },
    tableId: { type: String, default: '' },
  });
  const emits = defineEmits(['update:visible']);

  const fileTree = ref<TreeNodeData[]>([]);
  const buildTree = (list: CodePreviewRecord[]) => {
    const tree: TreeNodeData[] = [];
    // 指向children数组
    let pointer: any = null;
    list.forEach((file) => {
      pointer = tree;
      const paths = file.filePath.split('/');
      paths.forEach((path, index) => {
        // 对每一段路径处理
        const next = pointer.find((elem: TreeNodeData) => elem.title === path);
        if (next) {
          // 在当前指向节点的子节点中找到同名路径：进入
          pointer = next.children;
        } else {
          // 找不到，则创建，并进入
          const newNode = {
            title: path,
            key: paths.slice(0, index + 1).join('/'),
            children: [],
          };
          pointer.push(newNode);
          pointer = newNode.children;
        }
      });
    });
    return tree;
  };

  const displayingCode = ref<string>('');

  const loading = ref<boolean>(false);
  const fileList = ref<CodePreviewRecord[]>([]);
  const loadCode = async () => {
    loading.value = true;
    try {
      const { data } = await previewGeneratedCode(props.tableId);
      fileList.value = data;
      fileTree.value = buildTree(data);
    } finally {
      loading.value = false;
    }
  };

  watch(
    () => props.tableId,
    () => {
      loadCode();
    }
  );

  const collapsed = ref<boolean>(false);
  const onCollapse = () => {
    collapsed.value = !collapsed.value;
  };
  const size = ref<number>(0.25);

  const expandedNodes = ref<(string | number)[]>([]);
  const handleExpand = (expandKey: string | number | undefined) => {
    if (!expandKey) {
      return;
    }
    if (expandedNodes.value.find((elem) => elem === expandKey)) {
      // 已展开，则收起
      expandedNodes.value = expandedNodes.value.filter(
        (elem) => elem !== expandKey
      );
    } else {
      // 未展开，则展开
      expandedNodes.value = [...expandedNodes.value, expandKey];
    }
  };

  const openedFiles = ref<TreeNodeData[]>([]);
  const activeFile = ref<string | number>('');

  const selectedNodes = ref<(string | number)[]>([]);
  const onSelectNode = (
    selectedKeys: (string | number)[],
    {
      node,
    }: {
      selected?: boolean;
      selectedNodes: TreeNodeData[];
      node?: TreeNodeData;
      e?: Event;
    }
  ) => {
    selectedNodes.value = selectedKeys;
    if (!node) {
      return;
    }
    const openedFile = fileList.value.find(
      (elem) => elem.filePath === node.key
    );
    if (openedFile) {
      // 是末梢节点，可以展示
      displayingCode.value = openedFile.code;
      if (
        node?.key &&
        !openedFiles.value.find((elem) => elem.key === node?.key)
      ) {
        // 文件首次打开：加入到openedFiles中
        openedFiles.value = [...openedFiles.value, node];
      }
      activeFile.value = node.key || '';
    } else {
      // 是中间节点，展开或收起
      handleExpand(node.key);
    }
  };

  const onChangeTag = (value: string | number | boolean) => {
    if (value !== activeFile.value) {
      // 选中了其它tag，切换v-modal
      // 切换显示文件到其它tag对应的代码
      activeFile.value = value as string;
      selectedNodes.value = [value as string];
      displayingCode.value =
        fileList.value.find((elem) => elem.filePath === value)?.code || '';
    }
  };

  const resetTree = () => {
    fileList.value = [];
    fileTree.value = [];
    selectedNodes.value = [];
    expandedNodes.value = [];
  };
  const resetCode = () => {
    openedFiles.value = [];
    displayingCode.value = '';
  };
  const onClose = () => {
    resetTree();
    resetCode();
    emits('update:visible');
  };
</script>

<style lang="less" scoped>
  .preview-tree-wrapper {
    overflow-y: hidden;
  }

  .preview-tree-resource {
    float: left;
    width: 300px;
    padding: 30px;
  }

  .preview-tree-content {
    overflow: auto;
    border-left: 1px solid var(--color-border-1);
  }

  .preview-code-tags {
    :deep(.arco-radio) {
      margin-right: 0;
    }
  }
</style>
